package com.atqar.lock;

import java.util.concurrent.TimeUnit;

class ZiYuan {
    public static synchronized void a() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("email");


    }

    public synchronized void b() {
        System.out.println("sms");
    }

    public void hello() {
        System.out.println("hello");
    }
}


public class Lock8Demo {


    /*

    1-2
      一个对象里面如果有多个synchronized方法，某一个时刻内，只要一个线程去调用其中的一个synchronized方法了，
      其它的线程都只能等待，换句话说，某一个时刻内，只能有唯一一个线程去访问这些synchronized方法
      锁的是当前对象this，被锁定后，其它的线程都不能进入到当前对象的其它的synchronized方法
    3-4
      加个普通方法后发现和同步锁无关,被锁定后，其它的线程都不能进入到当前对象的其它的synchronized方法
     x 换成两个对象后，不是同一把锁了，情况立刻变化。
    5-6
      都换成静态同步方法后，情况又变化
      若是普通同步方法，new     this,  具体的一部部手机,所有的普通同步方法用的都是同一把锁——实例对象本身，
      若是静态同步方法，static  Class, 唯一的一个模板

    7-8
      一个线程试图访问同步代码时它首先必须得到锁，退出或抛出异常时必须释放锁。
      所有的普通同步方法用的都是同一把锁——实例对象本身，，就是new出来的具体实例对象本身
      也就是说如果一个实例对象的普通同步方法获取锁后，该实例对象的其他普通同步方法必须等待获取锁的方法释放锁后才能获取锁，
      可是别的实例对象的普通同步方法因为跟该实例对象的普通同步方法用的是不同的锁，所以不用等待该实例对象已获取锁的普通
      同步方法释放锁就可以获取他们自己的锁。
      所有的静态同步方法用的也是同一把锁——类对象本身，就是我们说过的唯一模板Class
      具体实例对象this和唯一模板Class，这两把锁是两个不同的对象，所以静态同步方法与普通同步方法之间是不会有竞态条件的。
      但是一旦一个静态同步方法获取锁后，其他的静态同步方法都必须等待该方法释放锁后才能获取锁
    */
    /*
    1 标准访问，请问先打印邮件还是短信    邮件
    2 邮件方法暂停4秒，请问先打印邮件还是短信  邮件
    3 新增普通hello方法，请问先打印邮件还是hello  hello,普通方法和锁无关
    4 变为两部手机，请问先打印邮件还是短信   换成两个对象后情况不一样了,不是同一把锁了不会发生抢锁
    5 两个静态同步方法，同一部手机，请问先打印邮件还是短信  邮件,static锁锁的是锁的是类模板不是实例化对象是同一把锁会抢锁
    6 两个静态同步方法，用两部手机，请问先打印邮件还是短信  邮件,static锁锁的是所得是类模板锁不是实例化对象,加对象没用还是同一把锁会抢锁
    7 一个静态同步方法，一个普通同步方法，用1部手机，请问先打印邮件还是短信  短信,一个是锁类模板一个锁的是实例化对象不是同一把锁不会发生抢锁
    8 一个静态同步方法，一个普通同步方法，用2部手机，请问先打印邮件还是短信  短信,一个是锁类模板一个锁的是实例化对象不是同一把锁不会发生抢锁
    */
    public static void main(String[] args) {

        ZiYuan zy1 = new ZiYuan();
        ZiYuan zy2 = new ZiYuan();

        new Thread(() -> {
            zy1.a();
        }, "a").start();

        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        //new Thread(()->{zy1.b();},"b").start();
        new Thread(() -> {
            zy2.b();
        }, "b").start();
        //new Thread(()->{zy1.hello();},"b").start();

    }


}
